package br.com.gbvbahia.vendas.controllers;

import br.com.gbvbahia.vendas.modelos.Cliente;
import br.com.gbvbahia.vendas.controllers.util.JsfUtil;
import br.com.gbvbahia.vendas.controllers.util.PaginationHelper;
import br.com.gbvbahia.vendas.beans.ClienteFacade;
import br.com.gbvbahia.vendas.beans.TelefoneFacade;
import br.com.gbvbahia.vendas.modelos.Endereco;
import br.com.gbvbahia.vendas.modelos.enums.Logradouro;
import br.com.gbvbahia.vendas.modelos.Telefone;
import br.com.gbvbahia.vendas.modelos.enums.TipoTelefone;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;

@Named("clienteController")
@SessionScoped
public class ClienteController implements Serializable {
    @EJB
    private TelefoneFacade telefoneFacade;
    @EJB
    private br.com.gbvbahia.vendas.beans.ClienteFacade ejbFacade;
    @Inject
    private PedidoController pedidoController;

    private Cliente current;
    private DataModel items = null;
    
    private PaginationHelper pagination;
    private int selectedItemIndex;
    private List<Telefone> telefone;
    private List<Endereco> endereco;
    private Telefone telCadastro = new Telefone();
    private Endereco endCadastro = new Endereco();
    private boolean showTelefone = false;
    private boolean showEndereco = false;
    private String telFiltro;
    private String nomeFiltro;
    
    public ClienteController() {
    }

        /**
     * Auto completar de matricula.
     *
     * @param varMatricula String
     * @return String
     */
    public List<String> complete(final String telefone) {
        return this.telefoneFacade.telefoneAutoComplete(telefone,JsfUtil.LIMIT_AUTO_COMPLETE);
    }
    
    public Cliente getSelected() {
        if (current == null) {
            current = new Cliente();
            selectedItemIndex = -1;
        }
        return current;
    }

    private ClienteFacade getFacade() {
        return ejbFacade;
    }

    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(10) {
                @Override
                public int getItemsCount() {
                    final int count = getFacade().contarClientesPorTelefone(telFiltro, nomeFiltro);
                    return count;
                }

                @Override
                public DataModel createPageDataModel() {
                    return new ListDataModel(getFacade().buscarClientesPorTelefone(telFiltro,nomeFiltro,
                            new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
                }
            };
        }
        return pagination;
    }
    
    public String fazerPedido(Cliente clientePedido){
        pedidoController.novoPedido(clientePedido);
        return "/compras/pedido/Create.xhtml";
    }

    public String prepareList() {
        recreateModel();
        return "List";
    }

    public String prepareView() {
        current = (Cliente) getItems().getRowData();
        selectedItemIndex = getPagination().getPageFirstItem() + getItems().getRowIndex();
        return "View";
    }

    public String prepareCreate() {
        current = new Cliente();
        reseteValues();
        selectedItemIndex = -1;
        return "Create";
    }

    public String create() {
        try {
            current.setTelefones(telefone);
            current.setEndereco(endereco);
            getFacade().create(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("ClienteCreated"));
            reseteValues();
            current = getFacade().find(current.getId());
            return prepareCreate();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String prepareEdit() {
        current = (Cliente) getItems().getRowData();
        selectedItemIndex = getPagination().getPageFirstItem() + getItems().getRowIndex();
        telefone = current.getTelefones();
        endereco = current.getEndereco();
        return "Create";
    }
    
      public String prepareEditView() {
        telefone = current.getTelefones();
        endereco = current.getEndereco();
        return "Create";
    }

    public String update() {
        try {
            current.setTelefones(telefone);
            current.setEndereco(endereco);
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("ClienteUpdated"));
            reseteValues();
            current = getFacade().find(current.getId());
            return "View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        current = (Cliente) getItems().getRowData();
        selectedItemIndex = getPagination().getPageFirstItem() + getItems().getRowIndex();
        performDestroy();
        recreatePagination();
        recreateModel();
        reseteValues();
        return "List";
    }

    public String destroyAndView() {
        performDestroy();
        recreateModel();
        updateCurrentItem();
        if (selectedItemIndex >= 0) {
            return "View";
        } else {
            // all items were removed - go back to list
            recreateModel();
            return "List";
        }
    }

    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("ClienteDeleted"));
            reseteValues();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void updateCurrentItem() {
        int count = getFacade().count();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count - 1;
            // go to previous page if last page disappeared:
            if (getPagination().getPageFirstItem() >= count) {
                pagination.previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            current = getFacade().findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
        }
    }

    public DataModel getItems() {
        if (items == null) {
            items = getPagination().createPageDataModel();
        }
        return items;
    }

    public void recreateModel() {
        items = null;
    }

    private void recreatePagination() {
        pagination = null;
    }

    public String next() {
        getPagination().nextPage();
        recreateModel();
        return "List";
    }

    public String previous() {
        getPagination().previousPage();
        recreateModel();
        return "List";
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    private void reseteValues() {
        telefone = null;
        endereco = null;
        telCadastro = new Telefone();
        endCadastro = new Endereco();
    }
    
    public Cliente getCliente(java.lang.Long id) {
        return ejbFacade.find(id);
    }

    public List<SelectItem> getTipoTelefoneSelect() {
        List<SelectItem> items = new ArrayList<SelectItem>();
        for (TipoTelefone o : TipoTelefone.values()) {
            items.add(new SelectItem(o, o.getTipo()));
        }
        return items;
    }

    public List<SelectItem> getTipoLogradouroSelect() {
                List<SelectItem> items = new ArrayList<SelectItem>();
        for (Logradouro o : Logradouro.values()) {
            items.add(new SelectItem(o, o.getLabel()));
        }
        return items;
    }
    
    public void removerTelefone(Telefone tel) {
        for (int i = telefone.size() - 1; i >= 0; i--) {
            if (telefone.get(i).equals(tel)) {
                telefone.remove(i);
            }
        }
    }
    
    public void removerEndereco(Endereco end){
        for(int i = endereco.size() - 1; i >= 0; i--){
            Endereco e = endereco.get(i);
            if(e.getNome().equalsIgnoreCase(end.getNome())
                    && (e.getNumero() != null && e.getNumero().equalsIgnoreCase(end.getNumero())
                    || (e.getBairro() != null && e.getBairro().equalsIgnoreCase(end.getBairro())))){
                endereco.remove(i);
            }
        }
    }

    public void adicionarTelefone() {
        if (telCadastro != null) {
            getTelefone().add(telCadastro);
            telCadastro = new Telefone();
            showTelefone = false;
        }
    }

    public void adicionarEndereco() {
        if(endCadastro != null){
            getEndereco().add(endCadastro);
            endCadastro = new Endereco();
            showEndereco = false;
        }
    }
    
    public List<Telefone> getTelefone() {
        if (telefone == null) {
            telefone = new ArrayList<Telefone>();
        }
        return telefone;
    }

    public void setTelefone(List<Telefone> telefone) {
        this.telefone = telefone;
    }

    public Telefone getTelCadastro() {
        return telCadastro;
    }

    public void setTelCadastro(Telefone telCadastro) {
        this.telCadastro = telCadastro;
    }

    public List<Endereco> getEndereco() {
        if(endereco == null){
            endereco = new ArrayList<Endereco>();
        }
        return endereco;
    }

    public void setEndereco(List<Endereco> endereco) {
        this.endereco = endereco;
    }

    public Endereco getEndCadastro() {
        return endCadastro;
    }

    public void setEndCadastro(Endereco endCadastro) {
        this.endCadastro = endCadastro;
    }

    public boolean isShowTelefone() {
        return showTelefone;
    }

    public void setShowTelefone(boolean showTelefone) {
        this.showTelefone = showTelefone;
    }

    public boolean isShowEndereco() {
        return showEndereco;
    }

    public void setShowEndereco(boolean showEndereco) {
        this.showEndereco = showEndereco;
    }

    public String getTelFiltro() {
        return telFiltro;
    }

    public void setTelFiltro(String telFiltro) {
        this.telFiltro = telFiltro;
    }

    public String getNomeFiltro() {
        return nomeFiltro;
    }

    public void setNomeFiltro(String nomeFiltro) {
        this.nomeFiltro = nomeFiltro;
    }

    public PedidoController getPedidoController() {
        return pedidoController;
    }

    public void setPedidoController(PedidoController pedidoController) {
        this.pedidoController = pedidoController;
    }

    @FacesConverter(forClass = Cliente.class)
    public static class ClienteControllerConverter implements Converter {

        @Override
        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            ClienteController controller = (ClienteController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "clienteController");
            return controller.getCliente(getKey(value));
        }

        java.lang.Long getKey(String value) {
            java.lang.Long key;
            key = Long.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Long value) {
            StringBuilder sb = new StringBuilder();
            sb.append(value);
            return sb.toString();
        }

        @Override
        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Cliente) {
                Cliente o = (Cliente) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Cliente.class.getName());
            }
        }
    }
}
